import socket
import threading
import struct
import time
import selectors
import queue
_clear              = 0b000000
_forward            = 0b000001
_backward           = 0b000010
_right              = 0b000100
_left               = 0b001000 
_inplace_right      = 0b010000 
_inplace_left       = 0b100000 

def debug(msg):
    print(f'[debug] {__file__}: {msg}')

q = queue.Queue(1)

class SyncThreading(threading.Thread):
    def __init__(self, addr):
        super(SyncThreading, self).__init__(daemon=True)
        self.completed_cb = None
        self.sel = selectors.DefaultSelector()
        self.addr = addr
        self.status_word = 0
        self.last_status_word = 0
        self._quit = False
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._socket.connect((self.addr, 2334))
        self._socket.setblocking(False)
        self.sel.register(self._socket, selectors.EVENT_READ | selectors.EVENT_WRITE, self.sock_handler)
    
    def sock_handler(self, conn, mask):
        if mask & selectors.EVENT_READ != 0:
            self.read_handler(conn)
        elif mask & selectors.EVENT_WRITE != 0:
            self.write_handler(conn)

    def read_handler(self, conn):
        data = conn.recv(4)
        data = struct.unpack("<i", data)
        self.status_word = 0
        if self.completed_cb is not None:
            self.completed_cb(data[0])

    def write_handler(self, conn):
        if not q.empty():
            time_stamp = 0
            op_code = q.get_nowait()
            if type(op_code) == tuple:
                op_code, time_stamp = op_code
            #print(f'{self.status_word} -- {op_code}')
            if self.status_word != op_code:
                self.status_word = op_code
                print('changed ', op_code)
                conn.send(struct.pack('<i',op_code))
            

    def set_quit(self):
        self._quit = True
    
    def run(self):
        while not self._quit:
            events = self.sel.select()
            for key, mask in events:
                cb = key.data
                cb(key.fileobj, mask)
            time.sleep(.02)

    def set_completed_callback(self, completed_cb):
        self.completed_cb = completed_cb

    #向前
    def forward(self):
        if not q.full():
            q.put_nowait(_forward)
    #向后
    def backward(self):
        if not q.full():
            q.put_nowait(_backward)
    
    #原地右转
    def inplace_right(self):
        if not q.full():
            q.put_nowait(_inplace_right)

    #原地左转
    def inplace_left(self):
        if not q.full():
            q.put_nowait(_inplace_left)
    
    def forward_right(self):
        self.status_word &= _clear
        self.status_word |= _forward
        self.status_word |= _right

    def forward_left(self):
        self.status_word &= _clear
        self.status_word |= _forward
        self.status_word |= _left

    def backward_right(self):
        self.status_word &= _clear
        self.status_word |= _backward
        self.status_word |= _right

    def backward_left(self):
        self.status_word &= _clear
        self.status_word |= _backward
        self.status_word |= _left

    def clear(self):
        while not q.empty():
            q.get_nowait()
        if not q.full():
            q.put_nowait(_clear)

        

#示例代码如下：
if __name__ == '__main__':
    def cb(flag):
        print(flag)
    import time
    
    sync_thread = SyncThreading('192.168.1.104')
    sync_thread.start() #先调用这个
    sync_thread.set_completed_callback(cb)
    # 有两个问题
    sync_thread.inplace_left()

    time.sleep(2)
    sync_thread.clear()
    sync_thread.set_quit() # set_quit之后线程就退出了
